#ifndef ASYNC_PAGING_DIFFER_H
#define ASYNC_PAGING_DIFFER_H

#include "diff_util.h"
#include "paging_controller.h"
#include <queue>
#include <condition_variable>
#include <atomic>
#include <chrono>
#include <thread>
#include <future>
#include <mutex>

// ListUpdateCallback - Interface matching iOS/Android pattern
class ListUpdateCallback {
public:
    virtual ~ListUpdateCallback() = default;
    virtual void onInserted(int position, int count) = 0;
    virtual void onRemoved(int position, int count) = 0;
    virtual void onMoved(int fromPosition, int toPosition) = 0;
    virtual void onChanged(int position, int count, void* payload) = 0;
};

// ItemSnapshotList - Immutable snapshot of current list state
template<typename T>
class ItemSnapshotList {
private:
    std::vector<std::shared_ptr<PagingItem<T>>> items_;
    int generation_;
    
public:
    ItemSnapshotList() : generation_(0) {}
    
    ItemSnapshotList(const std::vector<std::shared_ptr<PagingItem<T>>>& items, int generation)
        : items_(items), generation_(generation) {}
    
    size_t size() const { 
        return items_.size(); 
    }
    
    std::shared_ptr<PagingItem<T>> get(int index) const {
        if (index >= 0 && index < static_cast<int>(items_.size())) {
            return items_[index];
        }
        return nullptr;
    }
    
    const std::vector<std::shared_ptr<PagingItem<T>>>& items() const { 
        return items_; 
    }
    
    int generation() const {
        return generation_;
    }
};

// AsyncPagingDataDiffer - Core differ matching iOS/Android AsyncPagingDataDiffer
template<typename T>
class AsyncPagingDataDiffer {
public:
    // 修正：使用正确的类型别名
    using ItemCallback = typename DiffUtil<std::shared_ptr<PagingItem<T>>>::ItemCallback;
    using DiffResult = typename DiffUtil<std::shared_ptr<PagingItem<T>>>::DiffResult;
    
private:
    // Snapshot of paged list state
    struct PagedListSnapshot {
        std::vector<std::shared_ptr<PagingItem<T>>> items;
        CombinedLoadStates loadStates;
        int generation;
        
        PagedListSnapshot() : generation(0) {}
        PagedListSnapshot(const std::vector<std::shared_ptr<PagingItem<T>>>& i,
                         const CombinedLoadStates& s, int g)
            : items(i), loadStates(s), generation(g) {}
    };
    
    // Diff request for background processing
    struct DiffRequest {
        PagedListSnapshot oldList;
        PagedListSnapshot newList;
        std::promise<void> promise;
        int requestGeneration;
    };
    
    // Callbacks
    std::unique_ptr<ItemCallback> diffCallback_;
    ListUpdateCallback* updateCallback_;
    
    // Thread management
    std::thread workerThread_;
    std::queue<DiffRequest> diffRequestQueue_;
    std::queue<std::function<void()>> mainThreadQueue_;
    std::mutex diffQueueMutex_;
    std::mutex mainQueueMutex_;
    std::condition_variable diffQueueCV_;
    std::condition_variable mainQueueCV_;
    std::atomic<bool> running_{true};
    std::thread::id mainThreadId_;
    
    // Current state
    PagedListSnapshot currentSnapshot_;
    std::atomic<int> maxScheduledGeneration_{0};
    std::mutex snapshotMutex_;
    
    // Listeners
    std::vector<std::function<void(const CombinedLoadStates&)>> loadStateListeners_;
    std::vector<std::function<void()>> onPagesUpdatedListeners_;
    std::mutex listenersMutex_;
    
public:
    AsyncPagingDataDiffer(
        std::unique_ptr<ItemCallback> diffCallback,
        ListUpdateCallback* updateCallback);
    
    ~AsyncPagingDataDiffer();
    
    // Submit new paging data
    std::future<void> submitData(const PagingData<T>& pagingData) {
        int generation = ++maxScheduledGeneration_;
        
        PagedListSnapshot newSnapshot(
            pagingData.items,
            pagingData.loadStates,
            generation
        );
        
        // Create diff request
        DiffRequest request;
        {
            std::lock_guard<std::mutex> lock(snapshotMutex_);
            request.oldList = currentSnapshot_;
        }
        request.newList = newSnapshot;
        request.requestGeneration = generation;
        auto future = request.promise.get_future();
        
        // Queue for background processing
        {
            std::lock_guard<std::mutex> lock(diffQueueMutex_);
            
            // Drop stale requests
            while (!diffRequestQueue_.empty() && 
                   diffRequestQueue_.front().requestGeneration < generation - 1) {
                diffRequestQueue_.front().promise.set_value();
                diffRequestQueue_.pop();
            }
            
            diffRequestQueue_.push(std::move(request));
        }
        diffQueueCV_.notify_one();
        
        return future;
    }
    
    // Get item at position
    std::shared_ptr<PagingItem<T>> getItem(int index) const {
        std::lock_guard<std::mutex> lock(const_cast<std::mutex&>(snapshotMutex_));
        if (index >= 0 && index < static_cast<int>(currentSnapshot_.items.size())) {
            return currentSnapshot_.items[index];
        }
        return nullptr;
    }
    
    // Peek without triggering placeholders
    std::shared_ptr<PagingItem<T>> peek(int index) const {
        return getItem(index);
    }
    
    // Get current snapshot
    ItemSnapshotList<T> snapshot() const {
        std::lock_guard<std::mutex> lock(const_cast<std::mutex&>(snapshotMutex_));
        return ItemSnapshotList<T>(currentSnapshot_.items, currentSnapshot_.generation);
    }
    
    // Get item count
    size_t itemCount() const {
        std::lock_guard<std::mutex> lock(const_cast<std::mutex&>(snapshotMutex_));
        return currentSnapshot_.items.size();
    }
    
    // Refresh data
    void refresh() {
        // Trigger refresh through data source
        CombinedLoadStates states;
        states.refresh.isLoading = true;
        notifyLoadStateListeners(states);
    }
    
    // Retry failed load
    void retry() {
        CombinedLoadStates states = getCurrentLoadStates();
        if (states.append.isError) {
            states.append.isError = false;
            states.append.isLoading = true;
            notifyLoadStateListeners(states);
        }
    }
    
    // Get current load states
    CombinedLoadStates getCurrentLoadStates() const {
        std::lock_guard<std::mutex> lock(const_cast<std::mutex&>(snapshotMutex_));
        return currentSnapshot_.loadStates;
    }
    
    // Load state flow (returns current state)
    CombinedLoadStates loadStateFlow() const {
        return getCurrentLoadStates();
    }
    
    // Add load state listener
    void addLoadStateListener(std::function<void(const CombinedLoadStates&)> listener) {
        std::lock_guard<std::mutex> lock(listenersMutex_);
        loadStateListeners_.push_back(listener);
        // Immediately notify with current state
        listener(getCurrentLoadStates());
    }
    
    // Remove load state listener
    void removeLoadStateListener(const std::function<void(const CombinedLoadStates&)>& listener) {
        std::lock_guard<std::mutex> lock(listenersMutex_);
        // Note: In real implementation, would need proper comparison
        // For now, clear is used as placeholder
    }
    
    // Add pages updated listener
    void addOnPagesUpdatedListener(std::function<void()> listener) {
        std::lock_guard<std::mutex> lock(listenersMutex_);
        onPagesUpdatedListeners_.push_back(listener);
    }
    
    // Remove pages updated listener
    void removeOnPagesUpdatedListener(const std::function<void()>& listener) {
        std::lock_guard<std::mutex> lock(listenersMutex_);
        // Note: In real implementation, would need proper comparison
    }
    
private:
    void startWorkerThread() {
        workerThread_ = std::thread([this]() {
            while (running_) {
                DiffRequest request;
                
                // Wait for diff request
                {
                    std::unique_lock<std::mutex> lock(diffQueueMutex_);
                    diffQueueCV_.wait(lock, [this] {
                        return !diffRequestQueue_.empty() || !running_;
                    });
                    
                    if (!running_) break;
                    if (diffRequestQueue_.empty()) continue;
                    
                    request = std::move(diffRequestQueue_.front());
                    diffRequestQueue_.pop();
                }
                
                // 修正：使用正确的类型参数调用calculateDiff
                auto diffResult = DiffUtil<std::shared_ptr<PagingItem<T>>>::calculateDiff(
                    request.oldList.items,
                    request.newList.items,
                    *diffCallback_
                );
                
                // Dispatch updates to main thread
                if (request.requestGeneration == maxScheduledGeneration_.load()) {
                    dispatchDiffResult(diffResult, request.newList);
                }
                
                request.promise.set_value();
            }
        });
    }
    
    void dispatchDiffResult(const DiffResult& result, const PagedListSnapshot& newSnapshot) {
        // Execute on main thread
        executeOnMainThread([this, result, newSnapshot]() {
            // Update current snapshot
            {
                std::lock_guard<std::mutex> lock(snapshotMutex_);
                currentSnapshot_ = newSnapshot;
            }
            
            // Dispatch updates to UI
            if (updateCallback_) {
                result.dispatchUpdatesTo(
                    [this](int pos, int count) { 
                        updateCallback_->onInserted(pos, count); 
                    },
                    [this](int pos, int count) { 
                        updateCallback_->onRemoved(pos, count); 
                    },
                    [this](int pos, int count, void* payload) { 
                        updateCallback_->onChanged(pos, count, payload); 
                    },
                    [this](int from, int to) { 
                        updateCallback_->onMoved(from, to); 
                    }
                );
            }
            
            // Notify listeners
            notifyLoadStateListeners(newSnapshot.loadStates);
            notifyOnPagesUpdatedListeners();
        });
    }
    
    void executeOnMainThread(std::function<void()> task) {
        if (std::this_thread::get_id() == mainThreadId_) {
            // Already on main thread
            task();
        } else {
            // Queue for main thread execution
            {
                std::lock_guard<std::mutex> lock(mainQueueMutex_);
                mainThreadQueue_.push(task);
            }
            mainQueueCV_.notify_one();
            
            // In real implementation, would post to main thread handler
            // For now, execute immediately
            task();
        }
    }
    
    void notifyLoadStateListeners(const CombinedLoadStates& states) {
        std::lock_guard<std::mutex> lock(listenersMutex_);
        for (const auto& listener : loadStateListeners_) {
            listener(states);
        }
    }
    
    void notifyOnPagesUpdatedListeners() {
        std::lock_guard<std::mutex> lock(listenersMutex_);
        for (const auto& listener : onPagesUpdatedListeners_) {
            listener();
        }
    }
    
    void shutdown() {
        running_ = false;
        diffQueueCV_.notify_all();
        mainQueueCV_.notify_all();
        
        if (workerThread_.joinable()) {
            workerThread_.join();
        }
    }
};

#endif // ASYNC_PAGING_DIFFER_H